package sk.fiit.lulco.grafy;

import java.util.ArrayList;
import java.util.List;

/**
 * class for Vertex
 * 
 * @author Michal Lulco
 */
public class Vertex extends Item {

	private int id;
	
	private int color = 0;
	
	private boolean fixed = false;
	
	private int coloredNeighbours = 0;
	
	private int saturationDegree = 0;
	
	private int conflictCount = 0;
	
	private List<Vertex> neighbours = new ArrayList<Vertex>();
	
	private List<Integer> previousColors = new ArrayList<Integer>();
	
/*
	private List<Vertex> pageRankNeighbours = new ArrayList<Vertex>();
	
	private double pageRank;
	
	private double pageRankNextIteration;
*/
	/**
	 * constructor
	 * 
	 * @param	int	id
	 */
	public Vertex(int id) {
		this.id = id;
	}
	
	/**
	 * getter for id
	 * 
	 * @return	int
	 */
	public int getId() {
		return this.id;
	}

	/**
	 * getter for color
	 * 
	 * @return	int
	 */
	public int getColor() {
		return this.color;
	}
	
	private List<Integer> subList(List<Integer> originalList, int indexFrom, int indexTo) {
		List<Integer> list = new ArrayList<Integer>();
		for (int i = indexFrom; i < indexTo; i++) {
			list.add(originalList.get(i));
		}
		return list;
	}
	
	/**
	 * setter for color
	 * 
	 * @param	int	color
	 * @return	void
	 */
	public void setColor(int color) {
		int maxPreviousColorsSize = NewHEALAlgorithm.getMaxPreviousColorsSize();
		if (color != 0 && maxPreviousColorsSize > 0) {
			if (this.previousColors.size() == maxPreviousColorsSize) {
				this.previousColors = this.subList(previousColors, 1, maxPreviousColorsSize);
			}
			this.previousColors.add(color);
		}
//		if (!this.fixed) {
			int oldColor = this.color;
			this.color = color;
			if (color == 0 && oldColor != 0) {
				for (Vertex vertex : this.neighbours) {
					vertex.removeColoredNeighbour();
					vertex.updateSaturationDegree();
				}
			} else if (color != 0 && oldColor == 0) {
				for (Vertex vertex : this.neighbours) {
					vertex.addColoredNeighbour();
					vertex.updateSaturationDegree();
				}
			} else if (color != oldColor){
				for (Vertex vertex : this.neighbours) {
					vertex.updateSaturationDegree();
				}
			}
//		}
	}
	
	/**
	 * increase number of colored neighbours
	 * 
	 * @return	void
	 */
	private void addColoredNeighbour() {
		this.coloredNeighbours++;
	}
	
	/**
	 * decrease number of colored neighbours
	 * 
	 * @return	void
	 */
	private void removeColoredNeighbour() {
		this.coloredNeighbours--;
	}
	
	/**
	 * getter for neighbours
	 * 
	 * @return	List<Vertex>
	 */
	public List<Vertex> getNeighbours() {
		return this.neighbours;
	}
/*
	public void addPageRankNeighbour(Vertex pageRankNeighbour) {
		this.pageRankNeighbours.add(pageRankNeighbour);
	}
	
	public List<Vertex> getPageRankNeighbours() {
		return this.pageRankNeighbours;
	}
	
	public void setPageRankNeighbours(List<Vertex> pageRankNeighbours) {
		this.pageRankNeighbours = pageRankNeighbours;
	}
*/
	
	/**
	 * adds neighbour to the list
	 * 
	 * @param	Vertex	neighbour
	 * @return	void
	 */
	public void addNeighbour(Vertex neighbour) {
		this.neighbours.add(neighbour);
	}
	
	/**
	 * getter for degree
	 * 
	 * @return	int
	 */
	public int getDegree() {
		return this.neighbours.size();
	}
	
	/**
	 * getter for uncolored subgraph degree
	 * 
	 * @return	int
	 */
	public int getUncoloredSubgraphDegree() {
		return this.neighbours.size() - this.coloredNeighbours;
	}
	
	/**
	 * getter for saturation degree
	 * 
	 * @return	int
	 */
	public int getSaturationDegree() {
		return this.saturationDegree;
	}
	
	/**
	 * updater for saturation degree
	 * 
	 * @return	void
	 */
	private void updateSaturationDegree() {
		List<Integer> colors = new ArrayList<Integer>();
		for (Vertex neighbour : this.getNeighbours()) {
			if (neighbour.getColor() != 0 && !colors.contains(neighbour.getColor())) {
				colors.add(neighbour.getColor());
			}
		}
		this.saturationDegree = colors.size();
	}
	
	/**
	 * sets conflict count to 0 
	 */
	public void clearConflicts() {
		this.conflictCount = 0;
	}
	
	/**
	 * adds new conflict to conflict count
	 */
	public void addConflict() {
		this.conflictCount++;
	}
	
	/**
	 * getter for conflict count
	 * 
	 * @return	int
	 */
	public int getConflictsCount() {
		return this.conflictCount;
	}
	
	public void setFixed(boolean fixed) {
		this.fixed = fixed;
	}
	
	public boolean getFixed() {
		return this.fixed;
	}

	/**
	 * getter for page rank
	 * 
	 * @return	double
	 */
//	public double getPageRank() {
//		return this.pageRank;
//	}
	
	/**
	 * setter for page rank
	 * 
	 * @param	pageRank
	 * @return	void
	 */
//	public void setPageRank(double pageRank) {
//		this.pageRank = pageRank;
//	}
	
	/**
	 * getter for page rank next iteration
	 * 
	 * @return	double
	 */
//	public double getPageRankNextIteration() {
//		return this.pageRankNextIteration;
//	}
	
	/**
	 * setter for page rank next iteration
	 * 
	 * @param	pageRankNextIteration
	 * @return	void
	 */
//	public void setPageRankNextIteration(double pageRankNextIteration) {
//		this.pageRankNextIteration = pageRankNextIteration;
//	}
	
	public List<Integer> getPreviousColors() {
		return this.previousColors;
	}
	
	/**
	 * to string
	 *
	 * @return	String
	 */
//	public String toString() {
//		return Integer.toString(this.id);
//	}
}